package org.finesys.gateway.listener;

import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.finesys.commom.jackson.util.JacksonUtil;
import org.finesys.common.constants.CacheConstants;
import org.finesys.common.gateway.dynamic.route.FineRouteDefinition;
import org.finesys.common.gateway.dynamic.route.FineRouteDefinitionRepository;
import org.finesys.common.redis.core.mq.pubsub.AbstractPubSubMessageListener;
import org.finesys.system.api.dto.RouteConfDto;
import org.finesys.system.api.route.mq.RouteMessage;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONArray;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Component
@RequiredArgsConstructor
@Slf4j
public class RouteMessageConsumer extends AbstractPubSubMessageListener<RouteMessage> {

    private final RedisTemplate<String, Object> redisTemplate;
    private final FineRouteDefinitionRepository fineRouteDefinitionRepository;

    @Override
    public void onMessage(RouteMessage message) {
        /**清空缓存中的路由信息*/
        redisTemplate.delete(CacheConstants.ROUTE_KEY);
        if (log.isDebugEnabled()) {
            log.debug("接收到redis topic消息，缓存路由信息到Redis {}", message.getTopic());
        }
        List<RouteConfDto> routeConfList = message.getRouteConfDOList();
        Map<String, FineRouteDefinition> map = routeConfList.stream().map(this::convert).collect(Collectors.toMap(FineRouteDefinition::getId, Function.identity(), (key1, key2) -> key1));
        redisTemplate.opsForHash().putAll(CacheConstants.ROUTE_KEY, map);
        fineRouteDefinitionRepository.publishEvent();
        if (CollUtil.isEmpty(map)) {
            return;
        }
    }

    /**
     * 转换为RouteDefinition
     */
    private FineRouteDefinition convert(RouteConfDto routeConfDto) {
        FineRouteDefinition fineRouteDefinition = new FineRouteDefinition();
        PropertyMapper propertyMapper = PropertyMapper.get().alwaysApplyingWhenNonNull();
        propertyMapper.from(routeConfDto.getRouteId()).whenNonNull().to(fineRouteDefinition::setId);
        propertyMapper.from(routeConfDto.getName()).whenNonNull().to(fineRouteDefinition::setName);
        propertyMapper.from(routeConfDto.getUri()).whenNonNull().as(URI::create).to(fineRouteDefinition::setUri);
        propertyMapper.from(routeConfDto.getSortOrder()).whenNonNull().to(fineRouteDefinition::setOrder);
        propertyMapper.from(routeConfDto.getMetadata()).whenNonNull().as(v -> JacksonUtil.parseObject(v, Map.class)).to(fineRouteDefinition::setMetadata);
        propertyMapper.from(routeConfDto.getFilters()).whenNonNull().as(JSONArray::new).as(v -> v.toList(FilterDefinition.class)).to(fineRouteDefinition::setFilters);
        propertyMapper.from(routeConfDto.getPredicates()).whenNonNull().as(JSONArray::new).as(v -> v.toList(PredicateDefinition.class)).to(fineRouteDefinition::setPredicates);
        return fineRouteDefinition;
    }
}
